<?php
declare(strict_types=1);

namespace app\common\controller;

use app\common\auth\JwtAuth;
use app\common\model\Member;
use Psr\SimpleCache\InvalidArgumentException;
use think\App;
use think\ConfigApi;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
use think\facade\View;
use think\Hashlib;
use think\Request;
use think\response\Json;
use think\Validate;
use Exception;

/**
 * 控制器基础类
 */
abstract class AppBase
{
    /**
     * Request实例
     *
     * @var Request
     */
    protected Request $request;

    /**
     * 应用实例
     *
     * @var App
     */
    protected App $app;

    /**
     * 是否批量验证
     *
     * @var bool
     */
    protected bool $batchValidate = false;

    /**
     * 控制器中间件
     *
     * @var array
     */
    protected array $middleware = [];

    /**
     * GET请求
     *
     * @var array
     */
    protected array $get;

    /**
     * POST请求
     *
     * @var array
     */
    protected array $post;

    /**
     * PUT请求
     *
     * @var array
     */
    protected array $put;

    /**
     * 模块名
     *
     * @var string
     */
    protected string $module_name;

    /**
     * 控制器名
     *
     * @var string
     */
    protected string $controller_name;

    /**
     * 方法名
     *
     * @var string
     */
    protected string $action_name;

    /**
     * 域名
     *
     * @var string
     */
    protected string $domain_name;

    /**
     * 用户模型
     *
     * @var object
     */
    protected object $member_model;

    /**
     * token
     *
     * @var string
     */
    protected ?string $token = null;

    /**
     * user_cache
     *
     * @var string
     */
    protected static array $user_cache;

    /**
     * uuid
     *
     * @var int
     */
    protected int $uuid = 0;

    /**
     * uuid
     *
     * @var int
     */
    protected int $client_type = 0;

    /**
     * 构造方法
     *
     * @access public
     *
     * @param App $app 应用对象
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $this->request = $this->app->request;

        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {
        header("Content-Type: Text/Html;Charset =UTF-8");

        $this->member_model = new Member();

        $system_config = ConfigApi::lists();

        Config::set($system_config, 'system');

        // 获取Token
        $this->token = $this->request->header('token');

        if (!empty($this->token)) {
            // 检测环境
            $config_env = $system_config['config_env'] ? true : false;
            // 获取跨应用缓存
            self::$user_cache = $this->updateMemberWithInfo($this->token, $config_env);
        }

        // 系统信息
        View::assign([
            'system' => Config::has('system') ? Config::get('system') : '',
        ]);

        //获取request信息
        $this->initRequest();
    }

    /**
     * 初始化请求
     */
    protected function initRequest()
    {
        // GET接收信息
        $this->get = $this->request->get();
        // POST接受信息
        $this->post = $this->request->post();
        // PUST接受信息
        $this->put = $this->request->put();

        // 模块名
        $this->module_name = app('http')->getName();
        // 控制器名
        $this->controller_name = $this->request->controller(true);
        // 方法名
        $this->action_name = $this->request->action(true);
        // 域名
        $this->domain_name = $this->request->root(true);
        // IP
        $this->ip = $this->request->ip();

        // 请求动词
        defined('IS_GET') or define('IS_GET', $this->request->isGet());
        defined('IS_POST') or define('IS_POST', $this->request->isPost());
        defined('IS_PUT') or define('IS_PUT', $this->request->isPut());
        defined('IS_DELETE') or define('IS_DELETE', $this->request->isDelete());
        defined('IS_MOBILE') or define('IS_MOBILE', $this->request->isMobile());
    }

    /**
     * 验证数据
     *
     * @access protected
     *
     * @param array        $data     数据
     * @param string|array $validate 验证器名或者验证规则数组
     * @param array        $message  提示信息
     * @param bool         $batch    是否批量验证
     *
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
    {
        if (is_array($validate)) {
            $v = new Validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                [$validate, $scene] = explode('.', $validate);
            }
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
            $v = new $class();
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }

        $v->message($message);

        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }

        return $v->failException(true)->check($data);
    }

    /**
     * 数据模型
     *
     * @param array  $data
     * @param string $url
     * @param string $tip_name
     * @param string $model_name
     * @param string $validate_name
     * @param string $scene
     * @param array  $field
     * @param string $update_field
     * @param false  $is_debug
     *
     * @return Json
     */
    protected function writeData(array $data = [], string $url = '', string $tip_name = '提交', string $model_name = '', string $validate_name = '', string $scene = '', array $field = [], $update_field = 'id', $is_debug = false): Json
    {
        try {
            if (empty($model_name)) {
                throw new Exception("请设置接数据库模型");
            }

            // 第二步：检测是否建立模型验证
            if (!empty($validate_name)) {
                // 实例验证
                $validate = new $validate_name;

                if (!empty($scene)) {
                    // 场景验证
                    $validate_result = $validate->scene($scene)->check($data);
                } else {
                    $validate_result = $validate->check($data);
                }

                if (!$validate_result) {
                    throw new Exception($validate->getError());
                }

                if (isset($data[$update_field])) {
                    $model_object = $model_name::find($data[$update_field]);
                    //return $model_object;
                    $result = $model_object->save($data);
                } else {
                    //return self::jsonFail('測試2');
                    // 实例模型
                    $model = new $model_name;
                    $result = $model->save($data);
                }
            } else {
                if (isset($data[$update_field])) {
                    $model_object = $model_name::find($data[$update_field]);
                    //return $data;
                    $result = $model_object->save($data);
                } else {
                    // 实例模型
                    $model = new $model_name;
                    $result = $model->save($data);
                }
            }

            if ($result) {
                return self::jsonSuccess($tip_name, $url, $data);
            } else {
                return self::jsonFail($tip_name);
            }
        } catch (Exception $e) {
            return self::jsonFail($e->getMessage());
        }
    }

    /**
     * 请求成功
     *
     * @param string $msg
     * @param string $url
     * @param array  $data
     * @param int    $code
     * @param array  $fatal
     *
     * @return Json
     */
    protected static function jsonSuccess(string $msg = 'Success', string $url = '', array $data = [], int $code = 200, array $fatal = []): Json
    {
        return self::ajaxResponse($msg, $code, $url, $data, $fatal);
    }

    /**
     * 请求失败
     *
     * @param string $msg
     * @param string $url
     * @param array  $data
     * @param int    $code
     * @param array  $fatal
     *
     * @return Json
     */
    protected static function jsonFail(string $msg, string $url = '', array $data = [], int $code = 401, array $fatal = []): Json
    {
        return self::ajaxResponse($msg, $code, $url, $data, $fatal);
    }

    /**
     * Ajax请求
     *
     * @param string $msg
     * @param int    $code
     * @param string $url
     * @param array  $data
     * @param        $fatal
     *
     * @return Json
     */
    private static function ajaxResponse(string $msg, int $code, string $url, array $data, $fatal): Json
    {
        // 调试模式
        if ($code == 200) {
            $data = [
                'code' => $code,
                'msg'  => $msg,
                'url'  => $url,
                'data' => $data
            ];
        } else {
            $data = [
                'code'  => $code,
                'msg'   => $msg,
                'url'   => $url,
                'data'  => $data,
                'fatal' => $fatal
            ];
        }

        return json($data);
    }

    /**
     * 删除数据
     *
     * @param array  $data
     * @param string $url
     * @param string $tip_name
     * @param string $model_name
     *
     * @return Json
     */
    protected function delData(array $data = [], string $url = '', string $tip_name = '提交', string $model_name = ''): Json
    {
        try {
            if (empty($model_name)) {
                throw new Exception("请设置接数据库模型");
            }

            if (!isset($data['ids'])) {
                throw new Exception("缺少删除条件");
            }

            // 获取删除条件
            $id = (int)decode($data['ids']);

            // 实例模型
            $model = new $model_name;

            $model_object = $model->find($id);

            $result = $model_object->delete();

            if ($result) {
                return self::jsonSuccess($tip_name, $url);
            } else {
                return self::jsonFail($tip_name);
            }
        } catch (Exception $e) {
            return self::jsonFail($e->getMessage());
        }
    }

    /**
     * 获取用户信息
     *
     * @param string $token
     * @param bool   $config_env
     * @param bool   $is_sync
     *
     * @return array
     */
    protected function updateMemberWithInfo(string $token = '', bool $config_env = false, bool $is_sync = false): array
    {
        try {
            if ($token == 123456) {
                $this->uuid = 40;
                $this->client_type = 1;
                $member_data = Member::getMemberWithInfo($this->uuid, $this->client_type);
                return $member_data;
            }
            $jwtauth = JwtAuth::getInstance();
            $this->uuid = $jwtauth->setToken($token)->parserToken()->getUuid();
            $this->client_type = $jwtauth->setToken($token)->parserToken()->getClientType();
            if (Cache::store('redis')->get((string)'web_' . $token) && $is_sync == false) {
                // 修改
                $member_data = (array)Cache::store('redis')->get((string)'web_' . $token);
            } else {
                $member_data = Member::getMemberWithInfo($this->uuid, $this->client_type);
                Cache::store('redis')->set((string)"web_" . $token, $member_data, 3600 * 24 * 7);
            }
            return $member_data;
        } catch (InvalidArgumentException $e) {
            return [];
        }
    }

    /**
     * 创建目录
     *
     * @param $dir
     *
     * @return bool
     */
    protected static function mkdirs($dir): bool
    {
        if (!is_dir($dir)) {
            if (!self::mkdirs(dirname($dir))) {
                return false;
            }
            if (!mkdir($dir, 0777)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 安全加密工具
     *
     * @param int    $uuid
     * @param string $safety_code
     *
     * @return string
     */
    protected static function encryptionTool(int $uuid, string $safety_code): string
    {
        // 生成激活码
        $hashlib = new Hashlib();
        return $hashlib->encode($uuid, $safety_code);
    }

    /**
     * 安全解密工具
     *
     * @param string $hash
     *
     * @return array
     */
    protected static function decryptionTool(string $hash): array
    {
        $hashlib = new Hashlib();
        return $hashlib->decode($hash);
    }

    /**
     * Socket链接
     *
     * @param string $ip
     * @param int    $port
     * @param array  $data
     * @param float  $time
     *
     * @return mixed
     * @throws Exception
     */
    protected static function clientSocket(string $ip, int $port, array $data, float $time = 0.5)
    {
        // 创建TCP客户端
        $client = new \Swoole\Client(SWOOLE_SOCK_TCP);

        if (!$client->connect($ip, $port, $time)) throw new Exception("策略服务连接失败");

        $request_data = json_encode($data);

        if (!$client->send($request_data)) throw new Exception("策略服务请求失败");

        //从服务器接收数据
        $read_data = $client->recv();

        if (!$read_data) throw new Exception("接受策略服务失败");

        //打印从服务端接收到的数据
        if (!is_json($read_data)) throw new Exception("接受策略服务失败");

        $json_data = json_decode($read_data, true);

        //关闭连接
        $client->close();

        return $json_data;
    }
}
